import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import log.Log;
import easyJFC.JFrameOption;

public class MainJFrame extends JFrame {

	private static final long serialVersionUID = 2269971701250845501L;
	private static final int WIDTH = 380;
	private static final int HEIGHT = 300;

	private JTextField mText = new JTextField();
	private JButton btBackspace = new JButton("←");
	private JButton btClear = new JButton("CE");
	private JButton key_1 = new JButton("1");
	private JButton key_2 = new JButton("2");
	private JButton key_3 = new JButton("3");
	private JButton key_4 = new JButton("4");
	private JButton key_5 = new JButton("5");
	private JButton key_6 = new JButton("6");
	private JButton key_7 = new JButton("7");
	private JButton key_8 = new JButton("8");
	private JButton key_9 = new JButton("9");
	private JButton key_0 = new JButton("0");
	private JButton key_add = new JButton("+");
	private JButton key_sub = new JButton("-");
	private JButton key_mul = new JButton("*");
	private JButton key_div = new JButton("/");
	private JButton key_equ = new JButton("=");
	private JButton key_poi = new JButton(".");
	private JButton key_left = new JButton("(");
	private JButton key_right = new JButton(")");
	private CalcKeyActionListener listener;

	public MainJFrame() {
		super("计算器");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(WIDTH, HEIGHT);
		// 使用绝对布局
		this.setLayout(null);
		JFrameOption.setLookAndFeelAsWindows(this);
		JFrameOption.setMaximumSize(this, new Dimension(WIDTH, HEIGHT));
		this.setMinimumSize(new Dimension(WIDTH, HEIGHT));
		this.setFocusable(true);
		listener = new CalcKeyActionListener();
		this.addKeyListener(listener);
		init();

	}

	/**
	 * 初始化布局
	 */
	private void init() {
		mText.setHorizontalAlignment(JTextField.RIGHT);
		mText.setOpaque(true);
		mText.setBackground(Color.LIGHT_GRAY);
		mText.setEditable(false);
		int txtHeight = 45;
		mText.setBounds(3, 3, WIDTH - 20, txtHeight);
		mText.setText("0");
		this.add(mText);

		initButtonLocation(3, txtHeight + 6);

		add(btBackspace);
		add(btClear);
		add(key_1);
		add(key_2);
		add(key_3);

		add(key_add);
		add(key_sub);
		add(key_4);
		add(key_5);
		add(key_6);

		add(key_mul);
		add(key_div);
		add(key_7);
		add(key_8);
		add(key_9);

		add(key_left);
		add(key_right);
		add(key_0);
		add(key_poi);
		add(key_equ);

	}

	/**
	 * 初始化按键的位置。
	 * 
	 * @param initHeight
	 */
	private void initButtonLocation(final int initWidth, final int initHeight) {
		JButton[] buttons = { btBackspace, btClear, key_1, key_2, key_3, key_add, key_sub, key_4,
				key_5, key_6, key_mul, key_div, key_7, key_8, key_9, key_left, key_right, key_0,
				key_poi, key_equ };
		final int width = (WIDTH - 25) / 5;
		final int height = HEIGHT / 6;

		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 5; j++) {
				buttons[i * 5 + j].setBounds(j * (width + 1) + initWidth, i * (height + 1)
						+ initHeight, width, height);
				buttons[i * 5 + j].addActionListener(listener);
			}
		}
	}

	/**
	 * 按钮监听及键盘监听。
	 */
	class CalcKeyActionListener extends KeyAdapter implements ActionListener {
		/**
		 * 脚本解析引擎。
		 */
		ScriptEngineManager sem = new ScriptEngineManager();
		ScriptEngine se = sem.getEngineByName("js");

		/*
		 * 按钮回调方法。
		 */
		@Override
		public void actionPerformed(ActionEvent ae) {
			Object source = ae.getSource();
			if (!(source instanceof JButton)) {
				return;
			}

			JButton button = (JButton) source;
			if (button == btBackspace) {
				typeBackspace();
			} else if (button == btClear) {
				mText.setText("0");
			} else if (button == key_0) {
				typeNumber("0");
			} else if (button == key_1) {
				typeNumber("1");
			} else if (button == key_2) {
				typeNumber("2");
			} else if (button == key_3) {
				typeNumber("3");
			} else if (button == key_4) {
				typeNumber("4");
			} else if (button == key_5) {
				typeNumber("5");
			} else if (button == key_6) {
				typeNumber("6");
			} else if (button == key_7) {
				typeNumber("7");
			} else if (button == key_8) {
				typeNumber("8");
			} else if (button == key_9) {
				typeNumber("9");
			} else if (button == key_poi) {
				typePoint();
			} else if (button == key_add) {
				typeOperator("+");
			} else if (button == key_sub) {
				typeOperator("-");
			} else if (button == key_mul) {
				typeOperator("*");
			} else if (button == key_div) {
				typeOperator("/");
			} else if (button == key_left) {
				typeParenthesis("(");
			} else if (button == key_right) {
				typeParenthesis(")");
			} else if (button == key_equ) {
				calcExpression();
			} else {
				Log.w("other key press");
			}

			MainJFrame.this.requestFocus();
		}

		/**
		 * 按下或输入退格键。
		 */
		private void typeBackspace() {
			String text = mText.getText();
			if (text.length() > 1) {
				mText.setText(text.substring(0, text.length() - 1));
			} else {
				mText.setText("0");
			}
		}

		/**
		 * 按下或输入小数点。
		 */
		private void typePoint() {
			if (!mText.getText().endsWith(".")) {
				mText.setText(mText.getText() + ".");
			}
		}

		/**
		 * 计算表达式。
		 */
		private void calcExpression() {
			try {
				Log.i(mText.getText());
				String result = se.eval(mText.getText()).toString();
				mText.setText(mText.getText() + "=" + result);
			} catch (ScriptException e) {
				JOptionPane.showMessageDialog(null, "表达式有误。");
			}
		}

		/**
		 * 输入数字或按下数字。
		 * 
		 * @param text
		 *            按下或输入的数字。
		 */
		private void typeNumber(String text) {
			if (mText.getText().contains("=")) {
				mText.setText("0");
			}
			final String s = mText.getText();
			if (s.equals("0")) {
				mText.setText(text);
			} else {
				mText.setText(s + text);
			}
		}

		/**
		 * 输入或按下运算符。
		 * 
		 * @param text
		 *            输入或按下的运算符。
		 */
		private void typeOperator(String text) {
			if (mText.getText().contains("=")) {
				mText.setText("0");
			}
			final String s = mText.getText();
			if (isEndWithOperator(s)) {
				mText.setText(s.substring(0, s.length() - 1) + text);
			} else {
				mText.setText(s + text);
			}
		}

		/**
		 * 输入或按下括号。
		 * 
		 * @param text
		 *            括号。
		 */
		private void typeParenthesis(String text) {
			mText.setText(mText.getText() + text);
		}

		/**
		 * 表达式是否以运算符结尾。
		 * 
		 * @param s
		 *            当前的表达式。
		 * @return
		 */
		private boolean isEndWithOperator(String s) {
			return s.endsWith("+") || s.endsWith("-") || s.endsWith("*") || s.endsWith("/")
					|| s.endsWith("=");
		}

		/*
		 * 键盘按键回调方法。
		 */
		@Override
		public void keyTyped(KeyEvent e) {
			Log.i(Integer.toString(e.getKeyChar()));
			switch (e.getKeyChar()) {
			case KeyEvent.VK_0:
			case KeyEvent.VK_1:
			case KeyEvent.VK_2:
			case KeyEvent.VK_3:
			case KeyEvent.VK_4:
			case KeyEvent.VK_5:
			case KeyEvent.VK_6:
			case KeyEvent.VK_7:
			case KeyEvent.VK_8:
			case KeyEvent.VK_9:
				typeNumber(Integer.toString(e.getKeyChar() - KeyEvent.VK_0));
				break;
			case KeyEvent.VK_PERIOD:
				typePoint();
				break;
			case KeyEvent.VK_BACK_SPACE:
				typeBackspace();
				break;
			case KeyEvent.VK_ADD:
			case 43:
				typeOperator("+");
				break;
			case KeyEvent.VK_SUBTRACT:
			case KeyEvent.VK_MINUS:
				typeOperator("-");
				break;
			case KeyEvent.VK_MULTIPLY:
			case 42:
				typeOperator("*");
				break;
			case KeyEvent.VK_DIVIDE:
			case KeyEvent.VK_SLASH:
				typeOperator("/");
				break;
			case KeyEvent.VK_LEFT_PARENTHESIS:
			case KeyEvent.VK_DOWN:
				typeOperator("(");
				break;
			case KeyEvent.VK_RIGHT_PARENTHESIS:
			case 41:
				typeOperator(")");
				break;
			case KeyEvent.VK_EQUALS:
				calcExpression();
				break;
			default:
				break;
			}
		}
	}
}
